"""Definition of the BooksCatalog content type
"""
author__="Jaun Ignacio Barsola"
__docformat__ = 'plaintext'

# ZCA stuff
from zope.interface import implements
from zope.component import adapts

# Content type related stuff
from Products.Archetypes import atapi
from Products.ATContentTypes.content import folder
from Products.ATContentTypes.content.schemata import finalizeATCTSchema
from Products.ATContentTypes.interface import IATTopic

# import config stuff and interfaces
from itx.bookscatalog.interfaces import IBooksCatalog
from itx.bookscatalog.interfaces import ICatalogManager
from itx.bookscatalog.config import PROJECTNAME
from itx.bookscatalog import bookscatalogMessageFactory as _

# useful stuff
from Products.CMFCore.utils import getToolByName
# for caching
from plone.memoize import instance
import urllib
# Schema for the Catalog content type
# (we don't need any adittional fields for this CT)
BooksCatalogSchema = folder.ATFolderSchema.copy()

BooksCatalogSchema['title'].storage = atapi.AnnotationStorage()
BooksCatalogSchema['description'].storage = atapi.AnnotationStorage()

finalizeATCTSchema(BooksCatalogSchema, folderish=True, moveDiscussion=False)

# the actual BooksCatalog contet type class
class BooksCatalog(folder.ATFolder):
    """A container for books, like a catalog
    """
    implements(IBooksCatalog)

    portal_type = "Books Catalog"
    _at_rename_after_creation = True
    schema = BooksCatalogSchema

    # same explanation as in Book content type
    # (see notes on book.py please)
    # but be aware that this python properties
    # really use 'hidden' mutators and getters
    title = atapi.ATFieldProperty('title')
    description = atapi.ATFieldProperty('description')

# make AT aware of this class
atapi.registerType(BooksCatalog, PROJECTNAME)

# adapter for an IBooksCatalog
# Here we hold general methods like retriveing data, etc
class CatalogManager(object):
    """Manage BooksCatalog content types
    """
    implements(ICatalogManager)
    adapts(IBooksCatalog)
    def __init__(self, context):
        self.context = context
    
    def getBooks(self, query={}, max=None):
        """retrive list of books from the BooksCatalog,
        queried by quiery(a catalog query). If no books, return None.
        If max is not None, limit results to max books.
        """
        self.query = query
        self.max = max
        return self.books
    # Using the memoize decorator, we can 'memoize' (cache) 
    # the  books_results for an optimal result
    @property
    @instance.memoize
    def books(self):
        """retrive list of books from the BooksCatalog,
        queried by quiery(a catalog query). If no books, return None.
        If max is not None, limit results to max books.
        """
        book_query = self.query
        max = self.max
        books_results = [] 
        # we only want books of this (the context) BooksCatalog
        book_query['path'] = "/".join(self.context.getPhysicalPath())
        # We only want Book content types
        book_query['portal_type'] = 'Book' 
        # (we could return other BooksCatalogs if
        # we modify the content factory, so for now
        # the obove line is superfluous, because of the path restriction)
        
        # 'None' means no limit
        if max is not None:
            if type(max) == 'int':
                book_query['sort_limit'] = max
        catalog = getToolByName(self.context, 'portal_catalog')
        portal_workflow = getToolByName(self.context, 'portal_workflow') 
        # to form the url path...
        portal_properties = getToolByName(self.context, 'portal_properties')
        site_properties = portal_properties.site_properties
        use_view_action = site_properties.getProperty('typesUseViewActionInListings', ())
        
        # We don't want to wake up a large amount
        # of objects from ZODB (this is a book store, with
        # mabye thousands of thousands of books!)
        # so we get the stuff we want directly 
        # from the catalog for optimization matters
        for i, obj in enumerate(catalog.searchResults(book_query)): 
            if (i + 1) % 2 == 0:
                table_row_class = " itxTableRowEven"
            else:
                table_row_class = "itxTableRowOdd"
            url = obj.getURL()
            path = obj.getPath or "/".join(obj.getPhysicalPath())
            review_state = obj.review_state
            relative_url = obj.getURL(relative=True)
            obj_type = obj.portal_type
            created = obj.Date
            if obj_type in use_view_action:
                view_url = url + '/view'
            elif obj.is_folderish:
                view_url = url + "/folder_contents"
            else:
                view_url = url

            books_results.append(dict(
                # useful meta-data
                url = url,
                id = obj.getId,
                quoted_id = urllib.quote_plus(obj.getId),
                path = path,
                title_or_id = obj.pretty_title_or_id(),
                description = obj.Description,
                created = created,
                state_title = portal_workflow.getTitleForStateOnType(review_state,
                                                            obj_type),
                folderish = obj.is_folderish,
                relative_url = relative_url,
                view_url = view_url,
                table_row_class = table_row_class,
                is_expired = self.context.isExpired(obj),
                # and now the fields data
                # Note that all this fields needed by the template
                # were indexed with a GS profile, catalog.xml,
                # and thus searchable by the catalog. 
                isbn = obj.isbn,
                authors = obj.authors,
                summary = obj.summary,
                publisher = obj.publisher,
                edition = obj.edition,
                stock = obj.stock,
                available = obj.available,
            ))
        return books_results            
    
    # this is for deleting books from the BooksCatalog (the context)
    def delBooks(self, books_list):
        """ Delete books with id's given in books_list
        """
        #import pdb; pdb.set_trace()
        self.context.manage_delObjects(books_list)
